package src.ee.ioc.smaug.world.beings;


import src.ee.ioc.smaug.world.evolution.*;
import src.ee.ioc.smaug.world.*;
import src.ee.ioc.smaug.fsm.FiniteStateMachine;

/**
 * Describes the fsm as individual
 * @author Margarita Spichakova
 *
 */
public abstract class Individual {
    /**
     * Genotype
     */
    public  boolean[] genotype;
    /**
     * Fenotype
     */
    public FiniteStateMachine fenotype;
    
    /**
     * Genotype in decimal form
     */
    public int[] genotypeDec;
    
    /**
     * Fitness value of individual
     */
    private float fitness = 0;
    
    /**
     * Probability of being selected (roulette wheel selection)
     */
    public float probabilityOfBeingSelected = 0;
    
    public int[]stringEvaluation;
    
    abstract public void generateInDecinalForm();
    abstract public void generateInBinaryForm();
    abstract public void define();
    abstract public boolean isDead();
        
    abstract public void decode();
    abstract public void decodeBinToDec();
    abstract public void decodeDecToFSM();
    
    
    /**
     * Evaluation of individual
     */
    public void evaluate() {
        stringEvaluation =new int[Enviroment.inputData.size()];
        float fitness = 0;
        if (isDead()) {
            setFitness(0);
            return;
        }
        setFitness(0);
        decode();

        for (int i = 0; i < Enviroment.inputData.size(); i++) {
            String ins = "";
            String out1s = "";
            String out2s = "";

            ins = Enviroment.inputData.get(i);
            out1s = Enviroment.outputData.get(i);

            fenotype.setInString(ins);
            fenotype.runMachine();
            out2s = fenotype.getOutString();
            fenotype.setOutString("");
            int sd = StringDistances.apply(out1s, out2s);
            fitness +=sd;
            stringEvaluation[i]= sd;

        }
        fenotype = null;
        setFitness(fitness);
    }
    
    /**
     * Creates new Individual of corresponding type
     */
    public static Individual newIndividual() {
        switch (EnvDescription.beingType) {
        case MOORE_MACHINE_FIXED:
            return new  MooreSMFixedNumofStates();
        case MEALY_MACHINE_FIXED:
            return new  MealySMFixedNumofStates();
        case MOORE_MACHINE_MAX:
            return new  MooreSMMaxNumofStates();
        default:
            return new  MooreSMFixedNumofStates();

        }
    }    
    
    
    public void generate(){
        switch (EnvDescription.generating) {
        case GENERATING_BIN:
            generateInBinaryForm();
            break;
        case GENERATING_DEC:
            generateInDecinalForm();
            break;
        default:
            generateInBinaryForm();
            break;
        }
    }
    
    /**
     * @return fitness value
     */
    public float getFitness() {
        return fitness;
    }
    
    /**
     * Set fitness value
     * @param fitness
     */
    public void setFitness(float fitness) {
        this.fitness = fitness;
    }


}
